package gotnames.web.st;

import gotnames.Utils;
import gotnames.dm.Guess;
import gotnames.dm.KTrans;
import gotnames.dm.QueryBuilder;
import gotnames.dm.User;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import com.medallia.tiny.Clock;
import com.medallia.tiny.CollUtils;
import com.medallia.tiny.Empty;
import com.medallia.tiny.Funcs;

/**
 * Task which receives the form from {@link GuessNamesTask}. It displays the
 * same set of pictures, but under each picture is whether the user guessed
 * correctly or not.
 */
public class CheckGuessTask extends GotNamesTask {
	
	@Output interface Values {
		V<List<CheckGuessWebView>> PEOPLE = v();
	}
	
	/** Used to render each picture */
	public interface CheckGuessWebView {
		User getUser();
		boolean isAttemptGuess();
		boolean isCorrectGuess();
	}
	
	void action(final User user, DynamicInput dynamicInput, PersistenceManager pm) {
		Query q = pm.newQuery(User.class);
		q.setFilter("key != " + user.getKey() + " && groupKey == " + user.getGroupKey());
		Collection<User> allUsers = Utils.cast(q.execute());
		
		final Map<Long, User> userByKey = Funcs.buildMap(allUsers, User.KEY_FUNC);

		List<CheckGuessWebView> checkGuess = Empty.list();
		for (int index = 0; index < GuessNamesTask.NUM_PEOPLE; index++) {
			String correctUserKeyStr = dynamicInput.getInput("guess" + index, String.class);
			if (correctUserKeyStr == null)
				// Reached the end
				break;
			
			final Long correctUserKey = Long.valueOf(correctUserKeyStr);
			final User correctUser = userByKey.get(correctUserKey);
			if (correctUser == null)
				throw new IllegalStateException("Error in form, cannot find user with key " + correctUserKey);
			
			final String guessedFullName = dynamicInput.getInput(correctUserKeyStr, String.class);
			final boolean attemptGuess = guessedFullName != null;
			final boolean correctGuess;
			
			if (guessedFullName != null) {
				correctGuess = guessedFullName.equals(correctUser.getFullName());
				final Date now = Clock.now();
				
				new KTrans.Void(pm) {
					@Override protected void run() {
						Query query = pm.newQuery(Guess.class);
						query.setFilter(String.format("userKey == %s && correctUser == %s", user.getKey(), correctUserKey));
						Guess guess = CollUtils.getOneOrNull(Utils.<Collection<Guess>>cast(query.execute()));
						if (guess == null) {
							guess = new Guess();
							guess.setUserKey(user.getKey());
							guess.setCorrectUser(correctUserKey);
						} else {
							if (!Guess.guessAllowed(now, guess))
								throw new IllegalStateException("Error, user " + user.getFullName() + " is not currently allowed to guess on " + correctUser.getFullName());
						}
						
						guess.registerGuess(now, correctGuess);
						
						pm.makePersistent(guess);
					}
				}.go();
				new KTrans.Void(pm) {
					@Override protected void run() {
						QueryBuilder.begin(pm, User.class).getSingleByKey(user.getKey()).registerGuess(now, correctGuess);
					}
				}.go();
				
			} else {
				correctGuess = false;
			}
			
			checkGuess.add(new CheckGuessWebView() {
				@Override public User getUser() {
					return correctUser;
				}
				@Override public boolean isAttemptGuess() {
					return attemptGuess;
				}
				@Override public boolean isCorrectGuess() {
					return correctGuess;
				}
			});
		}
		attr(Values.PEOPLE, checkGuess);
	}

	@Override public String getPageTitle() { return "Guess names"; }

}
